package com.file.parser.socialsecurity;

import com.file.bo.ResponseData;
import com.file.bo.socialsecurity.GuangxiIndividualRecordSheet;
import com.file.bo.socialsecurity.GuangxiInsuranceParticipation;
import com.file.constant.ErrorCode;
import com.file.parser.BasePdfParser;
import com.file.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import technology.tabula.*;
import technology.tabula.detectors.SpreadsheetDetectionAlgorithm;
import technology.tabula.extractors.SpreadsheetExtractionAlgorithm;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
public class GuangxiSocialSecurityPdfParser extends BasePdfParser {

    public ResponseData<String> parseGuangxiSocialSecurityPdfParser(String daId, String filePath) {
        log.info("parseGuangxiSocialSecurityPdfParser started, daId:{}", daId);
        String json = null;
        try {
            if (filePath.contains("cbzm")) {
                GuangxiInsuranceParticipation GuangxiInsuranceParticipation = parseGuangxiInsuranceParticipation(filePath);
                json = JsonUtils.convertObjectToJson(GuangxiInsuranceParticipation);
            } else if (filePath.contains("qyd")) {
                GuangxiIndividualRecordSheet GuangxiIndividualRecordSheet = parseGuangxiIndividualRecordSheet(filePath);
                json = JsonUtils.convertObjectToJson(GuangxiIndividualRecordSheet);
            } else {
                log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_EXCEPTION.getCode(), daId, "", "", "parseGuangxiSocialSecurityPdfToJson failed, new type not supported");
                return new ResponseData<>(null, ErrorCode.FILE_PARSE_EXCEPTION.getCode(), ErrorCode.FILE_PARSE_EXCEPTION.getMsg());
            }
        } catch (Exception e) {
            log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_EXCEPTION.getCode(), daId, "", "", "parseGuangxiSocialSecurityPdfToJson failed", e);
            return new ResponseData<>(null, ErrorCode.FILE_PARSE_EXCEPTION.getCode(), ErrorCode.FILE_PARSE_EXCEPTION.getMsg());
        }

        log.info("parseGuangxiSocialSecurityPdfToJson completed, daId:{}", daId);
        return new ResponseData<>(json, ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg());
    }

    private void parseListToBO(List<List<String>> rowList, GuangxiInsuranceParticipation guangxiInsuranceParticipation) {
        String sectionName = "";
        List<GuangxiInsuranceParticipation.EnrollmentInfo> enrollmentInfos = new ArrayList<>();
        guangxiInsuranceParticipation.setEnrollmentInfo(enrollmentInfos);
        for (int i = 0; i < rowList.size(); i++) {
            List<String> cellList = rowList.get(i);
            if (StringUtils.equals(cellList.get(0), "单位编号")) {
                sectionName = "参保情况";
                continue;
            } else if (StringUtils.equals(cellList.get(0), "特 此 证 明")) {
                break;
            }
            switch (sectionName) {  //NOSONAR
                case "参保情况":
                    if (cellList.get(0).matches("[0-9]{9}")) {
                        GuangxiInsuranceParticipation.EnrollmentInfo enrollmentInfo = new GuangxiInsuranceParticipation.EnrollmentInfo();
                        enrollmentInfo.setOrganizationCode(cellList.get(0));
                        enrollmentInfo.setOrganizationName(cellList.get(1));
                        enrollmentInfo.setInsuranceType(cellList.get(2));
                        enrollmentInfo.setStartDate(cellList.get(3));
                        enrollmentInfo.setEndDate(cellList.get(4));
                        enrollmentInfo.setFullPayment(cellList.get(5));
                        enrollmentInfos.add(enrollmentInfo);
                    }
                    break;
            }
        }
    }

    private void parseListToBO(List<List<String>> rowList, GuangxiIndividualRecordSheet guangxiIndividualRecordSheet) {
        GuangxiIndividualRecordSheet.ContributionInfo contributionInfo = new GuangxiIndividualRecordSheet.ContributionInfo();
        GuangxiIndividualRecordSheet.IndividualAccountInfo individualAccountInfo = new GuangxiIndividualRecordSheet.IndividualAccountInfo();
        guangxiIndividualRecordSheet.setContributionInfo(contributionInfo);
        guangxiIndividualRecordSheet.setIndividualAccountInfo(individualAccountInfo);
        String sectionName = "";
        for (int i = 0; i < rowList.size(); i++) {
            List<String> cellList = rowList.get(i);
            if (StringUtils.equals(cellList.get(0), "个人月缴费基数")) {
                sectionName = "个人月缴费基数";
                continue;
            } else if (StringUtils.equals(cellList.get(0), "本年个人补缴欠费金额")) {
                sectionName = "本年个人补缴欠费金额";
                continue;
            } else if (StringUtils.equalsAny(cellList.get(0), "个人账户情况", "基本养老保险", "截至上年末个人账户累", "计储存额")) {
                sectionName = "基本养老保险";
                continue;
            } else if (StringUtils.equalsAny(cellList.get(0), "养老金领取情况(对在职职工不显示)", "月养老金水平")) {
                sectionName = "月养老金水平";
            } else if (StringUtils.equalsAny(cellList.get(0), "失业保险待遇享受情况(仅对失业人员显示)", "上次失业未领取失业", "保险金剩余月数")) {
                sectionName = "失业保险";
                continue;
            } else if (StringUtils.equalsAny(cellList.get(0), "工伤保险待遇享受情况(仅对工伤职工显示)", "工伤保险待遇", "享受开始年月")) {
                sectionName = "工伤保险待遇";
                continue;
            } else if (StringUtils.equalsAny(cellList.get(0), "一次性伤残", "补助金")) {
                sectionName = "一次性伤残";
                continue;
            }

            switch (sectionName) { //NOSONAR
                case "个人月缴费基数":
                    if (StringUtils.equals(cellList.get(0), "养老")) {
                        continue;
                    }
                    GuangxiIndividualRecordSheet.ContributionBaseInfo contributionBase = new GuangxiIndividualRecordSheet.ContributionBaseInfo();
                    GuangxiIndividualRecordSheet.PensionContribution pensionContribution = new GuangxiIndividualRecordSheet.PensionContribution();
                    GuangxiIndividualRecordSheet.UnemploymentContribution unemploymentContribution = new GuangxiIndividualRecordSheet.UnemploymentContribution();
                    GuangxiIndividualRecordSheet.InjuryContribution injuryContribution = new GuangxiIndividualRecordSheet.InjuryContribution();
                    contributionBase.setPension(cellList.get(0).replaceAll(" ", ""));
                    contributionBase.setUnemployment(cellList.get(1).replaceAll(" ", ""));
                    contributionBase.setInjury(cellList.get(2).replaceAll(" ", ""));
                    pensionContribution.setUnitContribution(cellList.get(3).replaceAll(" ", ""));
                    pensionContribution.setPersonalContribution(cellList.get(4).replaceAll(" ", ""));
                    unemploymentContribution.setUnitContribution(cellList.get(5).replaceAll(" ", ""));
                    unemploymentContribution.setPersonalContribution(cellList.get(6).replaceAll(" ", ""));
                    injuryContribution.setUnitContribution(cellList.get(7).replaceAll(" ", ""));
                    contributionInfo.setContributionBase(contributionBase);
                    contributionInfo.setPensionContribution(pensionContribution);
                    contributionInfo.setUnemploymentContribution(unemploymentContribution);
                    contributionInfo.setInjuryContribution(injuryContribution);
                    break;
                case "本年个人补缴欠费金额":
                    if (StringUtils.equalsAny(cellList.get(0), "养老", "")) {
                        continue;
                    }
                    GuangxiIndividualRecordSheet.ArrearsPaymentInfo currentYearArrearsPayment = new GuangxiIndividualRecordSheet.ArrearsPaymentInfo();
                    GuangxiIndividualRecordSheet.ArrearsPaymentInfo pastYearsContributionMonths = new GuangxiIndividualRecordSheet.ArrearsPaymentInfo();
                    GuangxiIndividualRecordSheet.ArrearsPaymentInfo actualContributionMonthsThisYear = new GuangxiIndividualRecordSheet.ArrearsPaymentInfo();
                    GuangxiIndividualRecordSheet.ArrearsPaymentInfo accumulatedArrearsMonths = new GuangxiIndividualRecordSheet.ArrearsPaymentInfo();
                    currentYearArrearsPayment.setPension(cellList.get(0).replaceAll(" ", ""));
                    currentYearArrearsPayment.setUnemployment(cellList.get(1).replaceAll(" ", ""));
                    pastYearsContributionMonths.setPension(cellList.get(2).replaceAll(" ", ""));
                    pastYearsContributionMonths.setUnemployment(cellList.get(3).replaceAll(" ", ""));
                    actualContributionMonthsThisYear.setPension(cellList.get(4).replaceAll(" ", ""));
                    actualContributionMonthsThisYear.setUnemployment(cellList.get(5).replaceAll(" ", ""));
                    accumulatedArrearsMonths.setPension(cellList.get(6).replaceAll(" ", ""));
                    accumulatedArrearsMonths.setUnemployment(cellList.get(7).replaceAll(" ", ""));
                    contributionInfo.setCurrentYearArrearsPayment(currentYearArrearsPayment);
                    contributionInfo.setPastYearsContributionMonths(pastYearsContributionMonths);
                    contributionInfo.setActualContributionMonthsThisYear(actualContributionMonthsThisYear);
                    contributionInfo.setAccumulatedArrearsMonths(accumulatedArrearsMonths);
                    break;
                case "基本养老保险":
                    GuangxiIndividualRecordSheet.BasicPensionInsuranceInfo basicPensionInsuranceInfo = new GuangxiIndividualRecordSheet.BasicPensionInsuranceInfo();
                    individualAccountInfo.setBasicPensionInsurance(basicPensionInsuranceInfo);
                    basicPensionInsuranceInfo.setAccumulatedStorageAmountLastYear(cellList.get(0).replaceAll(" ", ""));
                    basicPensionInsuranceInfo.setCurrentAccountingAmount(cellList.get(1).replaceAll(" ", ""));
                    basicPensionInsuranceInfo.setCurrentAccountExpense(cellList.get(2).replaceAll(" ", ""));
                    basicPensionInsuranceInfo.setCurrentAccountInterest(cellList.get(3).replaceAll(" ", ""));
                    basicPensionInsuranceInfo.setAccumulatedStorageAmountEndOfYear(cellList.get(4).replaceAll(" ", ""));
                    break;
                case "月养老金水平":
                    if (StringUtils.equals(cellList.get(0), "月养老金水平")) {
                        GuangxiIndividualRecordSheet.PensionBenefitInfo pensionBenefitInfo = new GuangxiIndividualRecordSheet.PensionBenefitInfo();
                        individualAccountInfo.setPensionBenefitInfo(pensionBenefitInfo);
                        pensionBenefitInfo.setMonthlyPensionLevel(cellList.get(1));
                        pensionBenefitInfo.setAnnualPensionAdjustmentAmount(cellList.get(3));
                    }
                    break;
                case "失业保险":
                    GuangxiIndividualRecordSheet.UnemploymentBenefitInfo unemploymentBenefitInfo = new GuangxiIndividualRecordSheet.UnemploymentBenefitInfo();
                    individualAccountInfo.setUnemploymentBenefitInfo(unemploymentBenefitInfo);
                    unemploymentBenefitInfo.setRemainingUnemploymentInsuranceMonths(cellList.get(0).replaceAll(" ", ""));
                    unemploymentBenefitInfo.setUnemploymentBenefitStartYearMonth(cellList.get(1).replaceAll(" ", ""));
                    unemploymentBenefitInfo.setUnemploymentBenefitMonths(cellList.get(2).replaceAll(" ", ""));
                    unemploymentBenefitInfo.setUnemploymentBenefitAmount(cellList.get(3).replaceAll(" ", ""));
                    unemploymentBenefitInfo.setCumulativeUnemploymentBenefitMonths(cellList.get(4).replaceAll(" ", ""));
                    unemploymentBenefitInfo.setCumulativeUnemploymentBenefitAmount(cellList.get(5).replaceAll(" ", ""));
                    break;
                case "工伤保险待遇":
                    GuangxiIndividualRecordSheet.InjuryBenefitInfo injuryBenefitInfo = new GuangxiIndividualRecordSheet.InjuryBenefitInfo();
                    individualAccountInfo.setInjuryBenefitInfo(injuryBenefitInfo);
                    injuryBenefitInfo.setInjuryBenefitStartYearMonth(cellList.get(0).replaceAll(" ", ""));
                    injuryBenefitInfo.setDisabilityGrade(cellList.get(1).replaceAll(" ", ""));
                    injuryBenefitInfo.setAnnualInjuryInsuranceFundPayment(cellList.get(2).replaceAll(" ", ""));
                    injuryBenefitInfo.setMedicalExpenses(cellList.get(3).replaceAll(" ", ""));
                    injuryBenefitInfo.setRehabilitationCosts(cellList.get(4).replaceAll(" ", ""));
                    injuryBenefitInfo.setAuxiliaryApplianceCost(cellList.get(5).replaceAll(" ", ""));
                    injuryBenefitInfo.setHospitalizationSubsidy(cellList.get(6).replaceAll(" ", ""));
                    injuryBenefitInfo.setTransportationExpenseOutsideTheRegion(cellList.get(7).replaceAll(" ", ""));
                    break;
                case "一次性伤残":
                    injuryBenefitInfo = individualAccountInfo.getInjuryBenefitInfo();
                    injuryBenefitInfo.setOneTimeDisabilityAllowance(cellList.get(0).replaceAll(" ", ""));
                    injuryBenefitInfo.setDisabilityAllowance(cellList.get(1).replaceAll(" ", ""));
                    injuryBenefitInfo.setLivingMaintenanceFee(cellList.get(2).replaceAll(" ", ""));
                    injuryBenefitInfo.setPensionDifferenceDueToInjury(cellList.get(3).replaceAll(" ", ""));
                    injuryBenefitInfo.setOneTimeMedicalAssistance(cellList.get(4).replaceAll(" ", ""));
                    injuryBenefitInfo.setOneTimeDeathBenefit(cellList.get(5).replaceAll(" ", ""));
                    injuryBenefitInfo.setFuneralAllowance(cellList.get(6).replaceAll(" ", ""));
                    injuryBenefitInfo.setDependentRelativesAllowance(cellList.get(7).replaceAll(" ", ""));
                    break;
            }
        }
    }

    private List<List<String>> parseFileToRowList(String filePath) {
        // 1. 读取文件
        File pdf = new File(filePath);

        //页面所有table的记录，每一个元素代表下面一条记录cellList
        List<List<String>> rowList = new ArrayList<>();

        // 2. pdfbox读取PDDocument
        try (PDDocument pdfDocument = PDDocument.load(pdf)) {
            // 3. tabula新建ObjectExtractor和NurminenDetectionAlgorithm，同时准备接收表格Rectangle的结构
            ObjectExtractor objectExtractor = new ObjectExtractor(pdfDocument);
            SpreadsheetDetectionAlgorithm detectionAlgorithm = new SpreadsheetDetectionAlgorithm();
            Map<Integer, List<Rectangle>> pageNumber2RectangleListMap = new HashMap<>();//key为页的序号， value为对应的Rectangle的list

            // 4. 获取每页的PageIterator
            PageIterator pageIterator = objectExtractor.extract();

            // 5. 解析每页的Rectangle
            // 如果单页pdf中有多个Rectangle，则解析出来的List<Rectangle>会有多个对象
            while (pageIterator.hasNext()) {
                Page page = pageIterator.next();
                List<Rectangle> rectangleList = detectionAlgorithm.detect(page);
                if (rectangleList.size() > 0) {
                    pageNumber2RectangleListMap.put(page.getPageNumber(), rectangleList);
                }
            }

            // 6.通过table位置获取表格具体内容
            SpreadsheetExtractionAlgorithm extractionAlgorithm = new SpreadsheetExtractionAlgorithm();

            // 如果单页pdf中有多个表格，则解析出来的List<Rectangle>会有多个对象
            for (Map.Entry<Integer, List<Rectangle>> entry : pageNumber2RectangleListMap.entrySet()) {
                Page page = objectExtractor.extract(entry.getKey());
                Rectangle rectangle = null;

                List<Rectangle> rectangleList = entry.getValue();
                for (Rectangle r : rectangleList) {
                    double rectangleHeight = r.getHeight();
                    if (Double.compare(rectangleHeight, 0) > 0) {
                        rectangle = r;
                        break;
                    }
                }
                if (rectangle == null) {
                    throw new RuntimeException("rectangle is null.");
                }

                if (entry.getKey() > 1) {
                    rectangle.setTop(rectangle.getTop());
                }
                rectangle.setBottom(rectangle.getBottom() + 500);
                Page area = page.getArea(rectangle);

                // 如果每页有多个表格，解析每一个table
                List<Table> tableList = extractionAlgorithm.extract(area);
                for (Table table : tableList) {
                    for (int i = 0; i < table.getRowCount(); i++) {
                        List<String> cellList = new ArrayList<>();//一条记录，每个单元格占一个元素
                        for (int j = 0; j < table.getColCount(); j++) {
                            cellList.add(table.getCell(i, j).getText(false));
                        }
                        rowList.add(cellList);
                    }
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }

        return rowList;
    }

    private GuangxiInsuranceParticipation parseGuangxiInsuranceParticipation(String filePath) {
        GuangxiInsuranceParticipation guangxiInsuranceParticipation = new GuangxiInsuranceParticipation();
        String pdfText = getPdfTextByStripper(filePath).replace(System.getProperty("line.separator", "\n"), StringUtils.EMPTY);
        String name = pdfText.substring(pdfText.lastIndexOf("缴费证明") + 4, pdfText.lastIndexOf("，个人编号")).trim();
        String personalId = pdfText.substring(pdfText.lastIndexOf("个人编号：") + 5, pdfText.lastIndexOf(",居民身份证")).trim();
        String idNo = pdfText.substring(pdfText.lastIndexOf("居民身份证号码：") + 8, pdfText.lastIndexOf("在我中心")).trim();
        String date = pdfText.substring(pdfText.lastIndexOf("日期 ") + 3, pdfText.lastIndexOf("社保机构盖章")).trim();
        String description = pdfText.substring(pdfText.lastIndexOf("说明：") + 3).trim().replace("\ufffd", "");
        guangxiInsuranceParticipation.setTitle("社会保险缴费证明");
        guangxiInsuranceParticipation.setName(name);
        guangxiInsuranceParticipation.setIdNumber(idNo);
        guangxiInsuranceParticipation.setPersonalId(personalId);
        guangxiInsuranceParticipation.setDate(date);
        guangxiInsuranceParticipation.setDescription(description);
        List<List<String>> rowList = parseFileToRowList(filePath);
        parseListToBO(rowList, guangxiInsuranceParticipation);
        return guangxiInsuranceParticipation;
    }

    private GuangxiIndividualRecordSheet parseGuangxiIndividualRecordSheet(String filePath) {
        GuangxiIndividualRecordSheet guangxiIndividualRecordSheet = new GuangxiIndividualRecordSheet();
        GuangxiIndividualRecordSheet.PersonalBasicInfo personalBasicInfo = new GuangxiIndividualRecordSheet.PersonalBasicInfo();
        GuangxiIndividualRecordSheet.InitialEnrollmentDates initialEnrollmentDates = new GuangxiIndividualRecordSheet.InitialEnrollmentDates();
        String pdfText = getPdfTextByStripper(filePath).replace(System.getProperty("line.separator", "\n"), StringUtils.EMPTY);
        String time = "";
        Matcher matcher = Pattern.compile("([0-9]{4}年[0-9]{1,2}月\\s*至\\s*[0-9]{4}年[0-9]{1,2}月)").matcher(pdfText);
        if (matcher.find()) {
            time = matcher.group(1).replaceAll(" ", "");
        }
        String personalId = pdfText.substring(pdfText.indexOf("个人编号: ") + 5, pdfText.indexOf("个人基本信息")).trim();
        String name = pdfText.substring(pdfText.indexOf("姓名") + 2, pdfText.indexOf("单位名称")).trim();
        String organizationName = pdfText.substring(pdfText.indexOf("单位名称") + 4, pdfText.indexOf("社会保障号码")).trim();
        String socialSecurityNumber = pdfText.substring(pdfText.indexOf("社会保障号码") + 6, pdfText.indexOf("首次参保日")).trim();
        String[] dates = pdfText.substring(pdfText.indexOf("工伤") + 2, pdfText.indexOf("缴费情况")).trim().split(" ");

        String address = pdfText.substring(pdfText.indexOf("地 址") + 5, pdfText.indexOf("联系电话")).trim();
        String phoneNumber = pdfText.substring(pdfText.indexOf("联系电话:") + 5, pdfText.indexOf("—————————")).trim();
        guangxiIndividualRecordSheet.setTime(time);
        guangxiIndividualRecordSheet.setPersonalId(personalId);
        guangxiIndividualRecordSheet.setAddress(address);
        guangxiIndividualRecordSheet.setPhoneNumber(phoneNumber);
        guangxiIndividualRecordSheet.setPersonalBasicInfo(personalBasicInfo);
        personalBasicInfo.setName(name);
        personalBasicInfo.setOrganizationName(organizationName);
        personalBasicInfo.setSocialSecurityNumber(socialSecurityNumber);
        personalBasicInfo.setInitialEnrollmentDates(initialEnrollmentDates);
        initialEnrollmentDates.setPension(dates[0]);
        initialEnrollmentDates.setUnemployment(dates[1]);
        initialEnrollmentDates.setInjury(dates[2]);
        List<List<String>> rowList = parseFileToRowList(filePath);
        parseListToBO(rowList, guangxiIndividualRecordSheet);
        return guangxiIndividualRecordSheet;
    }

    public static void main(String[] args) {
        GuangxiSocialSecurityPdfParser guangxiSocialSecurityPdfParser = new GuangxiSocialSecurityPdfParser();
        String json, filePath;
        // 参保证明
        filePath = "D:\\data\\file\\socialsecurity\\广西\\app-gjzwfw-dzsb_cbzm.pdf";
        json = guangxiSocialSecurityPdfParser.parseGuangxiSocialSecurityPdfParser("", filePath).getData();
        System.out.println("json = " + json);

        // 权益单
        filePath = "D:\\data\\file\\socialsecurity\\广西\\app-gjzwfw-dzsb_qyd.pdf";
        json = guangxiSocialSecurityPdfParser.parseGuangxiSocialSecurityPdfParser("", filePath).getData();
        System.out.println("json = " + json);
    }

}
